package com.xlh.common;

import com.xlh.dokka.api.exception.DokkaException;
import com.xlh.exception.*;
import com.xlh.exception.common.BadRequestException;
import com.xlh.exception.common.GlobalException;
import com.xlh.exception.common.NotFoundException;
import org.apache.catalina.connector.ClientAbortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


/**
 * 异常统一处理
 *
 * @author cheer
 */
@ControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class, BadRequestException.class})
    @ResponseBody
    public Result handleArgumentException(Exception e) {
        String message;
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            message = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        } else if (e instanceof BindException){
            BindException ex = (BindException) e;
            message = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        } else {
            message = e.getMessage();
        }
        return Result.error(ResultEnum.BAD_REQUEST, message);
    }

    @ExceptionHandler(NotFoundException.class)
    @ResponseBody
    public Result handleNotFoundException(NotFoundException e) {
        return Result.error(ResultEnum.NOT_FOUND, e.getMessage());
    }

    @ExceptionHandler(GlobalException.class)
    @ResponseBody
    public Result handleGlobalException(GlobalException e) {
        LOGGER.warn(e.getMessage());
        if (e.getResultEnum() != null) {
            return Result.error(e.getResultEnum());
        }
        return Result.error(ResultEnum.SERVER_ERROR, e.getMessage());
    }

    @ExceptionHandler(StatisticLockException.class)
    @ResponseBody
    public Result handleStatisticLockException(StatisticLockException e) {
        if (e.getResultEnum() != null) {
            return Result.error(e.getResultEnum());
        }
        return Result.error(ResultEnum.STATISTIC_LOCK_EXCEPTION, e.getMessage());
    }

    @ExceptionHandler(DokkaException.class)
    @ResponseBody
    public Result handleDokkaException(DokkaException e) {
        return Result.error(ResultEnum.SERVER_ERROR, e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result handleException(Exception e) throws Exception {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getResponse();
        response.addHeader("code-message", String.valueOf(ResultEnum.SERVER_ERROR.getCode()));
        if (e instanceof AccessDeniedException) {
            throw e;
        }
        if(e instanceof ClientAbortException) {
            LOGGER.warn("client abort exception");
            return null;
        }
        LOGGER.error(e.getMessage(), e);
        return Result.error(ResultEnum.SERVER_ERROR);
    }

    @ExceptionHandler(ClassUserException.class)
    @ResponseBody
    public Result handleClassUserException(ClassUserException e) {
        if (e.getResultEnum() != null) {
            return new Result<>(e.getResultEnum(), e.getData());
        }
        return Result.error(ResultEnum.SERVER_ERROR, e.getMessage());
    }

    @ExceptionHandler(DownloadFileException.class)
    @ResponseBody
    public Result handleDownloadFileException(HttpServletResponse response, DownloadFileException e) {
        response.addHeader("code", String.valueOf(ResultEnum.SERVER_ERROR.getCode()));
        try {
            response.addHeader("code-message", URLEncoder.encode(e.getMessage(), "UTF-8"));
        } catch (UnsupportedEncodingException e1) {
            return Result.error(ResultEnum.SERVER_ERROR);
        }
        return Result.error(ResultEnum.SERVER_ERROR, e.getMessage());
    }

    @ExceptionHandler(DeleteDealOperatingException.class)
    @ResponseBody
    public Result handleDeleteDealOperatingException(DeleteDealOperatingException e) {
        return Result.error(ResultEnum.DELETE_DEAL_EXCEPTION, e.getMessage());
    }

}
